package com.stream;

import com.alibaba.fastjson.JSON;

import java.util.*;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @Author:zxh
 * @Description: java.util.stream.Stream中方法熟悉
 * @Date: 2020/11/2
 * @Modified By:
 */
public class GitHubSream {

    /**
     * Stream是一个来自数据源的元素队列并支持聚合操作，更像是一个更高版本的Iterator,原始版本的Iterator，
     * 只能一个个遍历元素并完成相应操作。而使用Stream，只需要指定什么操作，
     * 如“过滤长度大于10的字符串”等操作，Stream会内部遍历并完成指定操作
     * <p>
     * 1.数据源：是Stream的来源，可以是集合、数组、I/O channel等转换而成的Stream；
     * 2.基本操作：类似于SQL语句一样的操作，比如filter,map,reduce,find,match,sort等操作。
     * <p>
     * 当我们操作一个流时，实际上会包含这样的执行过程：
     * 获取数据源-->转换成Stream-->执行操作，返回一个新的Stream-->再以新的Stream继续执行操作--->直至最后操作输出最终结果。
     */

    public void streamTest() {
        /**
         * 1.生成Stream的方式主要有这样几种：
         从接口Collection中和Arrays：
         Collection.stream();
         Collection.parallelStream(); //相较于串行流，并行流能够大大提升执行效率
         Arrays.stream(T array);

         2.Stream中的静态方法：
         Stream.of()；
         generate(Supplier s);
         iterate(T seed, UnaryOperator f);
         empty();

         3.其他方法
         Random.ints()
         BitSet.stream()
         Pattern.splitAsStream(java.lang.CharSequence)
         JarFile.stream()
         BufferedReader.lines()
         */

        //1.使用Collection中的方法和Arrays
        String[] stringArr = {"a", "b", "c", "d"};
        List<String> asList = Arrays.asList(stringArr);
        Stream<String> stream = asList.stream();
        Stream<String> stringStream = Arrays.stream(stringArr);

        //2. 使用Stream中提供的静态方法
        Stream<String> stringArr1 = Stream.of(stringArr);
        Stream<Double> generate = Stream.generate(Math::random);
        Stream<Object> empty = Stream.empty();
        Stream<Integer> iterate = Stream.iterate(1, i -> i++);
        System.out.println("Stream.iterate:" + stream);


        /**
         * 1.filter 对Stream中元素进行过滤
         * 过滤元素为空的字符串
         */
        long count = stream.filter(str -> str.isEmpty()).count();
        System.out.println("过滤元素为空的字符串" + count);

        /**
         * 2.map：对Stream中元素按照指定规则映射成另一个元素
         * map方法是一对一的关系，将stream中的每一个元素按照映射规则成另外一个元素，而如果是一对多的关系的话就需要使用flatmap方法。
         * 将每一个元素都添加字符串“_map”
         */
        stringArr1.map(str -> str + "_map").forEach(System.out::println);

        /**
         * 3.concat：对流进行合并操作
         * concat方法将两个Stream连接在一起，合成一个Stream
         */
        Stream.concat(Stream.of(1, 2, 3), Stream.of(4, 9, 8)).forEach(System.out::println);

        /**
         * 4.distinct：对流进行去重操作
         * 去除流中重复的元素
         */
        Stream<String> stringStream1 = Stream.of("a", "a", "b", "c");
        stringStream1.distinct().forEach(System.out::println);

        /**
         * 5.limit：限制流中元素的个数
         * 截取流中前两个元素：
         */
        Stream<String> stringStream2 = Stream.of("a", "a", "b", "c");
        stringStream2.limit(2).forEach(System.out::println);

        /**
         * 6.skip：跳过流中前几个元素
         * 丢掉流中前两个元素：
         */
        Stream<String> stringStream3 = Stream.of("a", "a", "b", "c");
        stringStream3.skip(2).forEach(System.out::println);

        /**
         * 7.peek：对流中每一个元素依次进行操作，类似于forEach操作
         */
        Stream.of("one", "two", "three", "four").filter(e -> e.length() > 3).peek(e -> System.out.println("Filter value:" + e)).
                map(String::toUpperCase).peek(e -> System.out.println("map value:" + e)).collect(Collectors.toList());

        /**
         * 8.sorted：对流中元素进行排序，可以通过sorted(Comparator<? super T> comparator)自定义比较规则
         */
        Stream<Integer> integerStream = Stream.of(1, 2, 4, 3);
        integerStream.sorted(Integer::compareTo).forEach(System.out::println);

        /**
         * 9.match：检查流中元素是否匹配指定的匹配规则
         * allMatch：Stream 中全部元素符合传入的 predicate，返回 true；
         * anyMatch：Stream 中只要有一个元素符合传入的 predicate，返回 true；
         * noneMatch：Stream 中没有一个元素符合传入的 predicate，返回 true。
         */
        Stream<Integer> integerStream2 = Stream.of(1, 2, 4, 3);
        boolean b = integerStream2.allMatch(integer -> integer > 3);
        System.out.println("allMatch:" + b);

        /**
         * 10.count：统计Stream中元素的个数
         *
         */
        Stream<String> stringArr2 = Stream.of(stringArr);
        long count1 = stringArr2.filter(str -> str.isEmpty()).count();
        System.out.println("count: " + count1);

        /**
         * 11.max/min：找出流中最大或者最小的元素
         */
        Stream<Integer> integerStream3 = Stream.of(1, 2, 4, 3);
        System.out.println(integerStream3.max(Integer::compareTo).get());
    }

    /**
     * 常见的Stream操作有这样几种：
     * 1.Intermediate（中间操作）:中间操作是指对流中数据元素做出相应转换或操作后依然返回为一个流Stream，仍然可以供下一次流操作使用。
     * 常用的有：map (mapToInt, flatMap 等)、 filter、 distinct、 sorted、 peek、 limit、 skip。
     * 2.Termial（结束操作）：是指最终对Stream做出聚合操作，输出结果。
     */
    public void streamMethod() {
        Collectors.joining(",");
        Collections.sort(Arrays.asList("3"));
        Collection.class.getFields();
        Collector.class.getFields();
        //boolean empty = CollectionUtils.isEmpty();
        Stream.builder().accept("2");
        Set<Object> collect = Stream.builder().add("2").add("34").add("89").build().collect(Collectors.toSet());
        System.out.println("collect: " + collect);


    }

    /**
     * 一个集合过滤另一个集合
     * @param args
     */
    public void listFilterList(){
        List<Student> studentList = new ArrayList<>();
        studentList.add(new Student("张三"));
        studentList.add(new Student("lisi2"));
        List<String> stringList = new ArrayList<>();
        stringList.add("zhangsan");
        stringList.add("lisi");

        //以stringList为主，返回没有匹配的
        List<String> collect = stringList.stream().filter(str -> studentList.stream().noneMatch(stu -> stu.getName().equals(str))).collect(Collectors.toList());
        System.out.println(collect.toString());

    }

    /**
     * 一个对象集合，根据对象某个字段进行分组且分组后根据XX字段排序并且取第一个对象
     * @param args
     */
    public void streamList(){
        List<Student> studentList = new ArrayList<>();
        Student student = new Student("李四", "", 1, 2);
        Student student1 = new Student("李四", "", 2, 3);
        Student student2 = new Student("王五", "1", 3, 4);
        Student student3 = new Student("王五", "11", 4, 5);
        Student student4 = new Student("王五", "", 5, 6);
        studentList.add(student);studentList.add(student1);studentList.add(student2);studentList.add(student3);
        studentList.add(student4);
        List<Student> collect = studentList.stream().sorted(Comparator.comparing(Student::getNameTwo).reversed()).limit(2).collect(Collectors.toList());
        //System.out.println("collect： "+JSON.toJSONString(collect));
       // studentList.stream().collect(Collectors.groupingBy(Student::getName)).entrySet().stream().flatMap()
       /* stringListMap.entrySet().stream().sorted(Comparator.comparing(Student::getNameTwo)).collect(Collectors.toList())
        sorted.forEach(k->{
            System.out.println(k.getKey()+": "+ JSON.toJSONString(k.getValue()));
        });*/
        //System.out.println("输出："+sorted.toString());

    }

    public static void main(String[] args) {
//        new GitHubSream().listFilterList();
        new GitHubSream().streamList();
        //new GitHubSream().streamTest();
        //new GitHubSream().streamMethod();

//        HashMap<Object, Object> hashMap = new HashMap<>();
//        hashMap.put("one",34);
//        hashMap.put("two",45);
//        Set<Map.Entry<Object, Object>> entries = hashMap.entrySet();
//        for (Map.Entry<Object, Object> map:entries) {
//            map.getKey();
//        }
//        System.out.println(entries);
    }
}
